//
//  NSDate+Helper.m
//

#import "NSDate+Helper.h"

const long long SECONDS_IN_YEAR = 31556900;
const NSInteger SECONDS_IN_MONTH_28 = 2419200;
const NSInteger SECONDS_IN_MONTH_29 = 2505600;
const NSInteger SECONDS_IN_MONTH_30 = 2592000;
const NSInteger SECONDS_IN_MONTH_31 = 2678400;
const NSInteger SECONDS_IN_WEEK = 604800;
const NSInteger SECONDS_IN_DAY = 86400;
const NSInteger SECONDS_IN_HOUR = 3600;
const NSInteger SECONDS_IN_MINUTE = 60;
const NSInteger MILLISECONDS_IN_DAY = 86400000;

static const unsigned int allCalendarUnitFlags = NSCalendarUnitYear | NSCalendarUnitQuarter | NSCalendarUnitMonth | NSCalendarUnitWeekOfYear | NSCalendarUnitWeekOfMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond | NSCalendarUnitNanosecond | NSCalendarUnitEra | NSCalendarUnitWeekday | NSCalendarUnitWeekdayOrdinal | NSCalendarUnitWeekOfYear;

@implementation NSDate (Helper)

+ (NSCalendar*)sharedCalendar {
    return NSCalendar.currentCalendar;
}

+ (NSDateFormatter *)sharedDateFormatter {
    static NSDateFormatter *_displayFormatter = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _displayFormatter = [[NSDateFormatter alloc] init];
        [_displayFormatter setTimeZone:[NSTimeZone localTimeZone]];
//        [_displayFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
    });
    return _displayFormatter;
}

+ (NSCalendar*)chineseCalendar {
    static NSCalendar *_calendar = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierChinese];
    });
    return _calendar;
}

+ (NSCalendar*)gregorianCalendar {
    static NSCalendar *_calendar = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
    });
    return _calendar;
}

+ (NSDate *)dateFromString:(NSString *)string withFormat:(NSString *)format {
    NSDateFormatter *formatter = [self sharedDateFormatter];
    [formatter setDateFormat:format];
    return [formatter dateFromString:string];
}

+ (NSDate*)dateFromSQLDateString:(NSString*)string {
    return [[self class] dateFromString:string withFormat:@"yyyy-MM-dd HH:mm:ss"];
}

+ (NSDate*)dateFromTimeStamp:(NSTimeInterval)timeStamp {
    return [NSDate dateWithTimeIntervalSince1970:timeStamp];
}

+ (NSDate *)dateWithYear:(NSInteger)year month:(NSInteger)month day:(NSInteger)day {
    return [[self class] dateWithYear:year month:month day:day hour:0 minute:0 second:0 nanosecond:0];
}

+ (NSDate *)dateWithYear:(NSInteger)year month:(NSInteger)month day:(NSInteger)day hour:(NSInteger)hour minute:(NSInteger)minute second:(NSInteger)second {
    return [[self class] dateWithYear:year month:month day:day hour:hour minute:minute second:second nanosecond:0];
}

+ (NSDate *)dateWithYear:(NSInteger)year month:(NSInteger)month day:(NSInteger)day
                    hour:(NSInteger)hour minute:(NSInteger)minute second:(NSInteger)second nanosecond:(NSInteger)nanosecond {
    NSDateComponents *components = [[NSDateComponents alloc] init];
    components.year   = year;
    components.month  = month;
    components.day    = day;
    components.hour   = hour;
    components.minute = minute;
    components.second = second;
    components.nanosecond = nanosecond;
    return [[[self class] sharedCalendar] dateFromComponents:components];
}

+ (BOOL)timeStampIsToday:(NSTimeInterval)timeStamp {
    return [[[self class] dateFromTimeStamp:timeStamp] isToday];
}

+ (BOOL)timeStampIsSameDay:(NSTimeInterval)timeStamp timeStamp2:(NSTimeInterval)timeStamp2 {
    NSDate *date = [[self class] dateFromTimeStamp:timeStamp];
    NSDate *date2 = [[self class] dateFromTimeStamp:timeStamp2];
    return [date isSameDay:date2];
}

+ (BOOL)stringIsToday:(NSString*)string withFormat:(NSString*)format {
    NSDate *date = [[self class] dateFromString:string withFormat:format];
    return date ? [date isToday] : NO;
}

+ (BOOL)stringIsSameDay:(NSString*)string string2:(NSString*)string2 withFormat:(NSString*)format {
    NSDate *date = [[self class] dateFromString:string withFormat:format];
    NSDate *date2 = [[self class] dateFromString:string2 withFormat:format];
    return [date isSameDay:date2];
}

+ (BOOL)stringIsSameDay:(NSString*)string withFromat:(NSString*)format string2:(NSString*)string2 withFormat2:(NSString*)format2 {
    NSDate *date = [[self class] dateFromString:string withFormat:format];
    NSDate *date2 = [[self class] dateFromString:string2 withFormat:format2];
    return [date isSameDay:date2];
}

- (NSTimeInterval)timeStamp {
    return [self timeIntervalSince1970];
}

- (NSDateComponents*)dateComponents {
    return [[[self class] sharedCalendar] components:allCalendarUnitFlags fromDate:self];
}

//毫秒
- (NSInteger)nanosecond {
    NSCalendar *calendar = [[self class] sharedCalendar];
    NSDateComponents *components = [calendar components:(NSCalendarUnitNanosecond) fromDate:self];
    return [components nanosecond];
}

//秒
- (NSInteger)second {
    NSCalendar *calendar = [[self class] sharedCalendar];
    NSDateComponents *components = [calendar components:(NSCalendarUnitSecond) fromDate:self];
    return [components second];
}

//分钟
- (NSInteger)minute {
    NSCalendar *calendar = [[self class] sharedCalendar];
    NSDateComponents *components = [calendar components:(NSCalendarUnitMinute) fromDate:self];
    return [components minute];
}

//小时
- (NSInteger)hour {
    NSCalendar *calendar = [[self class] sharedCalendar];
    NSDateComponents *components = [calendar components:(NSCalendarUnitHour) fromDate:self];
    return [components hour];
}

//天
- (NSInteger)day {
    NSCalendar *calendar = [[self class] sharedCalendar];
    NSDateComponents *components = [calendar components:(NSCalendarUnitDay) fromDate:self];
    return [components day];
}

//星期
- (NSInteger)weekday {
    NSDateComponents *components = [[[self class] sharedCalendar] components:(NSCalendarUnitWeekday) fromDate:self];
    return [components weekday];
}

- (BOOL)isWeekend {
    NSCalendar *calendar = [[self class] sharedCalendar];
    NSRange weekdayRange = [calendar maximumRangeOfUnit:NSCalendarUnitWeekday];
    NSDateComponents *components = [calendar components:NSCalendarUnitWeekday fromDate:self];
    NSUInteger weekdayOfSomeDate = [components weekday];

    BOOL result = NO;
    if (weekdayOfSomeDate == weekdayRange.location || weekdayOfSomeDate == weekdayRange.length) {
        result = YES;
    }
    return result;
}

- (NSInteger)weekOfMonth {
    NSCalendar *calendar = [[self class] sharedCalendar];
    NSDateComponents *components = [calendar components:(NSCalendarUnitWeekOfMonth) fromDate:self];
    return [components weekOfMonth];
}

//本年第多少周
- (NSInteger)weekOfYear {
    NSCalendar *calendar = [[self class] sharedCalendar];
    NSDateComponents *components = [calendar components:(NSCalendarUnitWeekOfYear) fromDate:self];
    return [components weekOfYear];
}

- (NSInteger)yearForWeekOfYear {
    NSCalendar *calendar = [[self class] sharedCalendar];
    NSDateComponents *components = [calendar components:(NSCalendarUnitYearForWeekOfYear) fromDate:self];
    return [components yearForWeekOfYear];
}

//月
- (NSInteger)month {
    NSCalendar *calendar = [[self class] sharedCalendar];
    NSDateComponents *components = [calendar components:(NSCalendarUnitMonth) fromDate:self];
    return [components month];
}

// 时代
- (NSInteger)era {
    NSCalendar *calendar = [[self class] sharedCalendar];
    NSDateComponents *components = [calendar components:(NSCalendarUnitEra) fromDate:self];
    return [components era];
}

//年
- (NSInteger)year {
    NSCalendar *calendar = [[self class] sharedCalendar];
    NSDateComponents *components = [calendar components:(NSCalendarUnitYear) fromDate:self];
    return [components year];
}

- (NSInteger)weekdayOrdinal {
    NSCalendar *calendar = [[self class] sharedCalendar];
    NSDateComponents *components = [calendar components:(NSCalendarUnitWeekdayOrdinal) fromDate:self];
    return [components weekdayOrdinal];
}

- (NSInteger)quarter {
    NSCalendar *calendar = [[self class] sharedCalendar];
    NSDateComponents *components = [calendar components:(NSCalendarUnitQuarter) fromDate:self];
    return [components quarter];
}

- (BOOL)isToday {
    NSCalendar *calendar = [[self class] sharedCalendar];
    NSDateComponents *components = [calendar components:(NSCalendarUnitEra|NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay) fromDate:[NSDate date]];
    NSDate *today = [calendar dateFromComponents:components];
    components = [calendar components:(NSCalendarUnitEra|NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay) fromDate:self];
    NSDate *otherDate = [calendar dateFromComponents:components];
    return [today isEqualToDate:otherDate];
}

- (BOOL)isTomorrow {
    NSCalendar *calendar = [[self class] sharedCalendar];
    NSDateComponents *components = [calendar components:(NSCalendarUnitEra|NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay) fromDate:[[NSDate date] addingDays:1]];
    NSDate *tomorrow = [calendar dateFromComponents:components];
    components = [calendar components:(NSCalendarUnitEra|NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay) fromDate:self];
    NSDate *otherDate = [calendar dateFromComponents:components];
    return [tomorrow isEqualToDate:otherDate];
}

-(BOOL)isYesterday{
    NSCalendar *calendar = [[self class] sharedCalendar];
    NSDateComponents *components = [calendar components:(NSCalendarUnitEra|NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay) fromDate:[[NSDate date] subtractingDays:1]];
    NSDate *tomorrow = [calendar dateFromComponents:components];
    components = [calendar components:(NSCalendarUnitEra|NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay) fromDate:self];
    NSDate *otherDate = [calendar dateFromComponents:components];
    return [tomorrow isEqualToDate:otherDate];
}

// 是否同一天
- (BOOL)isSameDay:(NSDate*)date {
    NSCalendar *calendar = [[self class] sharedCalendar];
    NSDateComponents *components = [calendar components:(NSCalendarUnitEra|NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay) fromDate:self];
    NSDate *dateOne = [calendar dateFromComponents:components];
    components = [calendar components:(NSCalendarUnitEra|NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay) fromDate:date];
    NSDate *dateTwo = [calendar dateFromComponents:components];
    return [dateOne isEqualToDate:dateTwo];
}

- (BOOL)isSameDayWithDateString:(NSString*)string withFormat:(NSString*)format {
    NSDate *date = [[self class] dateFromString:string withFormat:format];
    return date ? [self isSameDay:date] : NO;
}

- (BOOL)isSunday {
    return self.weekday==1;
}

- (BOOL)isMonday {
    return self.weekday==2;
}

- (BOOL)isTuesday {
    return self.weekday==3;
}

- (BOOL)isWednesday {
    return self.weekday==4;
}

- (BOOL)isThurday {
    return self.weekday==5;
}

- (BOOL)isFriday {
    return self.weekday==6;
}

- (BOOL)isSaturday {
    return self.weekday==7;
}

+ (NSString*)dateStringFromString:(NSString*)string format:(NSString*)format toFormat:(NSString*)toFromat {
    return [[[self class] dateFromString:string withFormat:format] stringWithFormat:toFromat];
}

+ (NSString*)dateStringWithTimeStamp:(NSTimeInterval)timeStamp withFormat:(NSString*)format {
    return [[[self class] dateFromTimeStamp:timeStamp] stringWithFormat:format];
}

+ (NSString*)sqlDateStringWithTimeStamp:(NSTimeInterval)timeStamp {
    return [[[self class] dateFromTimeStamp:timeStamp] stringWithSQLDateFormat];
}

+ (NSString*)nanosecondDateStringWithTimeStamp:(NSTimeInterval)timeStamp {
    return [[[self class] dateFromTimeStamp:timeStamp] stringWithNanosecond];
}

- (NSString*)stringWithFormat:(NSString *)format {
    NSDateFormatter *formatter = [[self class] sharedDateFormatter];
    [formatter setDateFormat:format];
    return [formatter stringFromDate:self];
}

- (NSString*)stringWithNanosecond {
    return [self stringWithFormat:@"yyyy/MM/dd HH:mm:ss.SSS"];
}

- (NSString*)stringWithSQLDateFormat {
    return [self stringWithFormat:@"yyyy-MM-dd HH:mm:ss"];
}

-(NSInteger)yearsFrom:(NSDate *)date {
    NSCalendar *calendar = [[self class] sharedCalendar];
    NSDate *earliest = [self earlierDate:date];
    NSDate *latest = (earliest == self) ? date : self;
    NSInteger multiplier = (earliest == self) ? -1 : 1;
    NSDateComponents *components = [calendar components:NSCalendarUnitYear fromDate:earliest toDate:latest options:0];
    return multiplier*components.year;
}

-(NSInteger)monthsFrom:(NSDate *)date {
    NSCalendar *calendar = [[self class] sharedCalendar];
    NSDate *earliest = [self earlierDate:date];
    NSDate *latest = (earliest == self) ? date : self;
    NSInteger multiplier = (earliest == self) ? -1 : 1;
    NSDateComponents *components = [calendar components:allCalendarUnitFlags fromDate:earliest toDate:latest options:0];
    return multiplier*(components.month + 12*components.year);
}

-(NSInteger)weeksFrom:(NSDate *)date {
    NSCalendar *calendar = [[self class] sharedCalendar];
    NSDate *earliest = [self earlierDate:date];
    NSDate *latest = (earliest == self) ? date : self;
    NSInteger multiplier = (earliest == self) ? -1 : 1;
    NSDateComponents *components = [calendar components:NSCalendarUnitWeekOfYear fromDate:earliest toDate:latest options:0];
    return multiplier*components.weekOfYear;
}

-(NSInteger)daysFrom:(NSDate *)date {
    NSCalendar *calendar = [[self class] sharedCalendar];
    NSDate *earliest = [self earlierDate:date];
    NSDate *latest = (earliest == self) ? date : self;
    NSInteger multiplier = (earliest == self) ? -1 : 1;
    NSDateComponents *components = [calendar components:NSCalendarUnitDay fromDate:earliest toDate:latest options:0];
    return multiplier*components.day;
}

-(double)hoursFrom:(NSDate *)date{
    return ([self timeIntervalSinceDate:date])/SECONDS_IN_HOUR;
}

-(double)minutesFrom:(NSDate *)date{
    return ([self timeIntervalSinceDate:date])/SECONDS_IN_MINUTE;
}

-(double)secondsFrom:(NSDate *)date{
    return [self timeIntervalSinceDate:date];
}

-(NSInteger)yearsUntil{
    return [self yearsLaterThan:[NSDate date]];
}

-(NSInteger)monthsUntil{
    return [self monthsLaterThan:[NSDate date]];
}

-(NSInteger)weeksUntil{
    return [self weeksLaterThan:[NSDate date]];
}

-(NSInteger)daysUntil{
    return [self daysLaterThan:[NSDate date]];
}

-(double)hoursUntil{
    return [self hoursLaterThan:[NSDate date]];
}

-(double)minutesUntil{
    return [self minutesLaterThan:[NSDate date]];
}

-(double)secondsUntil{
    return [self secondsLaterThan:[NSDate date]];
}

#pragma mark Time Ago

-(NSInteger)yearsAgo{
    return [self yearsEarlierThan:[NSDate date]];
}

-(NSInteger)monthsAgo{
    return [self monthsEarlierThan:[NSDate date]];
}

-(NSInteger)weeksAgo{
    return [self weeksEarlierThan:[NSDate date]];
}

-(NSInteger)daysAgo{
    return [self daysEarlierThan:[NSDate date]];
}

-(double)hoursAgo{
    return [self hoursEarlierThan:[NSDate date]];
}

-(double)minutesAgo{
    return [self minutesEarlierThan:[NSDate date]];
}

-(double)secondsAgo{
    return [self secondsEarlierThan:[NSDate date]];
}

-(NSInteger)yearsEarlierThan:(NSDate *)date{
    return ABS(MIN([self yearsFrom:date], 0));
}

-(NSInteger)monthsEarlierThan:(NSDate *)date{
    return ABS(MIN([self monthsFrom:date], 0));
}

-(NSInteger)weeksEarlierThan:(NSDate *)date{
    return ABS(MIN([self weeksFrom:date], 0));
}

-(NSInteger)daysEarlierThan:(NSDate *)date{
    return ABS(MIN([self daysFrom:date], 0));
}

-(double)hoursEarlierThan:(NSDate *)date{
    return ABS(MIN([self hoursFrom:date], 0));
}

-(double)minutesEarlierThan:(NSDate *)date{
    return ABS(MIN([self minutesFrom:date], 0));
}

-(double)secondsEarlierThan:(NSDate *)date{
    return ABS(MIN([self secondsFrom:date], 0)); 
}

-(NSInteger)yearsLaterThan:(NSDate *)date{
    return MAX([self yearsFrom:date], 0);
}

-(NSInteger)monthsLaterThan:(NSDate *)date{
    return MAX([self monthsFrom:date], 0);
}

-(NSInteger)weeksLaterThan:(NSDate *)date{
    return MAX([self weeksFrom:date], 0);
}

-(NSInteger)daysLaterThan:(NSDate *)date{
    return MAX([self daysFrom:date], 0);
}

-(double)hoursLaterThan:(NSDate *)date{
    return MAX([self hoursFrom:date], 0);
}

-(double)minutesLaterThan:(NSDate *)date{
    return MAX([self minutesFrom:date], 0);
}

-(double)secondsLaterThan:(NSDate *)date{
    return MAX([self secondsFrom:date], 0);
}

-(BOOL)isEarlierThan:(NSDate *)date{
    if (self.timeIntervalSince1970 < date.timeIntervalSince1970) {
        return YES;
    }
    return NO;
}

-(BOOL)isLaterThan:(NSDate *)date{
    if (self.timeIntervalSince1970 > date.timeIntervalSince1970) {
        return YES;
    }
    return NO;
}

-(BOOL)isEarlierThanOrEqualTo:(NSDate *)date{
    if (self.timeIntervalSince1970 <= date.timeIntervalSince1970) {
        return YES;
    }
    return NO;
}

-(BOOL)isLaterThanOrEqualTo:(NSDate *)date{
    if (self.timeIntervalSince1970 >= date.timeIntervalSince1970) {
        return YES;
    }
    return NO;
}

- (BOOL)isBetween:(NSDate *)date date2:(NSDate *)date2 {
    return (([self isLaterThan:date] && [self isEarlierThan:date2]) || ([self isLaterThan:date2] && [self isEarlierThan:date]));
}

- (NSUInteger)daysInMonth {
    NSCalendar *calendar = [[self class] sharedCalendar];
    NSRange days = [calendar rangeOfUnit:NSCalendarUnitDay inUnit:NSCalendarUnitMonth forDate:self];
    return days.length;
}

- (NSUInteger)daysInYear {
   return [self isLeapYear] ? 366 : 365;
}

- (NSUInteger)dayOfYear {
    NSCalendar *calendar = [[self class] sharedCalendar];
    return [calendar ordinalityOfUnit:NSCalendarUnitDay inUnit:NSCalendarUnitYear forDate:self];
}

- (NSDate*)addingYears:(NSInteger)years  {
    NSDateComponents *components = [[NSDateComponents alloc] init];
    components.year = years;
    NSCalendar *calendar = [[self class] sharedCalendar];
    return [calendar dateByAddingComponents:components toDate:self options:0];
}

- (NSDate*)addingMonths:(NSInteger)months  {
    NSDateComponents *components = [[NSDateComponents alloc] init];
    components.month = months;
    NSCalendar *calendar = [[self class] sharedCalendar];
    return [calendar dateByAddingComponents:components toDate:self options:0];
}

- (NSDate*)addingWeeks:(NSInteger)weeks {
    NSDateComponents *components = [[NSDateComponents alloc] init];
    components.weekOfYear = weeks;
    NSCalendar *calendar = [[self class] sharedCalendar];
    return [calendar dateByAddingComponents:components toDate:self options:0];
}

- (NSDate*)addingDays:(NSInteger)days {
    NSDateComponents *components = [[NSDateComponents alloc] init];
    components.day = days;
    NSCalendar *calendar = [[self class] sharedCalendar];
    return [calendar dateByAddingComponents:components toDate:self options:0];
}

- (NSDate*)addingHours:(NSInteger)hours {
    NSDateComponents *components = [[NSDateComponents alloc] init];
    components.hour = hours;
    NSCalendar *calendar = [[self class] sharedCalendar];
    return [calendar dateByAddingComponents:components toDate:self options:0];
}

- (NSDate*)addingMinutes:(NSInteger)minutes {
    NSDateComponents *components = [[NSDateComponents alloc] init];
    components.minute = minutes;
    NSCalendar *calendar = [[self class] sharedCalendar];
    return [calendar dateByAddingComponents:components toDate:self options:0];
}

- (NSDate*)addingSeconds:(NSInteger)seconds {
    NSDateComponents *components = [[NSDateComponents alloc] init];
    components.second = seconds;
    NSCalendar *calendar = [[self class] sharedCalendar];
    return [calendar dateByAddingComponents:components toDate:self options:0];
}

- (NSDate*)addingNanoSeconds:(NSInteger)nanoseconds {
    NSDateComponents *components = [[NSDateComponents alloc] init];
    components.nanosecond = nanoseconds;
    NSCalendar *calendar = [[self class] sharedCalendar];
    return [calendar dateByAddingComponents:components toDate:self options:0];
}

- (NSDate*)addingYears:(NSInteger)years months:(NSInteger)months days:(NSInteger)days
              hours:(NSInteger)hours minutes:(NSInteger)minutes seconds:(NSInteger)seconds nanoseconds:(NSInteger)nanoseconds {
    NSDateComponents *components = [[NSDateComponents alloc] init];
    components.year = years;
    components.month = months;
    components.day = days;
    components.hour = hours;
    components.minute = minutes;
    components.second = seconds;
    components.nanosecond = nanoseconds;
    NSCalendar *calendar = [[self class] sharedCalendar];
    return [calendar dateByAddingComponents:components toDate:self options:0];
}

- (NSDate*)subtractingYears:(NSInteger)years{
    return [self addingYears:-1*years];
}

- (NSDate*)subtractingMonths:(NSInteger)months{
    return [self addingMonths:-1*months];
}

- (NSDate*)subtractingWeeks:(NSInteger)weeks{
    return [self addingWeeks:-1*weeks];
}

- (NSDate*)subtractingDays:(NSInteger)days{
    return [self addingDays:-1*days];
}

- (NSDate*)subtractingHours:(NSInteger)hours{
    return [self addingHours:-1*hours];
}

- (NSDate*)subtractingMinutes:(NSInteger)minutes{
    return [self addingMinutes:-1*minutes];
}

- (NSDate*)subtractingSeconds:(NSInteger)seconds{
    return [self addingSeconds:-1*seconds];
}

- (NSDate*)subtractingNanoseconds:(NSInteger)nanosecond{
    return [self addingNanoSeconds:-1*nanosecond];
}

- (NSDate*)subtractingYears:(NSInteger)years months:(NSInteger)months days:(NSInteger)days
                      hours:(NSInteger)hours minutes:(NSInteger)minutes seconds:(NSInteger)seconds nanoseconds:(NSInteger)nanoseconds {
    return [self addingYears:-1*years months:-1*months days:-1*days hours:-1*hours minutes:-1*minutes seconds:-1*seconds nanoseconds:-1*nanoseconds];
}

- (NSDate*)beginOfYear {
    return [[self class] dateWithYear:[self year] month:1 day:1];
}

- (NSDate*)endOfYear {
    return [[self class] dateWithYear:[self year] month:12 day:31];
}

- (NSDate*)beginOfMonth {
    NSCalendar *calendar = [[self class] sharedCalendar];
    NSDateComponents *components = [calendar components:NSCalendarUnitYear|NSCalendarUnitMonth fromDate:self];
    return [[self class] dateWithYear:components.year month:components.month day:1];
}

- (NSDate*)endOfMonth {
    NSCalendar *calendar = [[self class] sharedCalendar];
    NSDateComponents *components = [calendar components:NSCalendarUnitYear|NSCalendarUnitMonth fromDate:self];
    NSRange days = [calendar rangeOfUnit:NSCalendarUnitDay inUnit:NSCalendarUnitMonth forDate:self];
    return [[self class] dateWithYear:components.year month:components.month day:days.length];
}

- (NSDate*)beginOfWeek {
    NSCalendar *calendar = [[self class] sharedCalendar];
    NSDate *beginningOfWeek = nil;
    BOOL ok = [calendar rangeOfUnit:NSCalendarUnitWeekOfMonth startDate:&beginningOfWeek interval:nil forDate:self];
    if (ok) {
        return beginningOfWeek;
    }
    NSDateComponents *weekdayComponents = [calendar components:NSCalendarUnitWeekday fromDate:self];

    NSDateComponents *componentsToSubtract = [[NSDateComponents alloc] init];
    [componentsToSubtract setDay: 0 - ([weekdayComponents weekday] - 1)];
    beginningOfWeek = [calendar dateByAddingComponents:componentsToSubtract toDate:self options:0];
    NSDateComponents *components = [calendar components:(NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay) fromDate:beginningOfWeek];
    return [calendar dateFromComponents:components];
}

- (NSDate*)beginOfDay {
    NSCalendar *calendar = [[self class] sharedCalendar];
    NSDateComponents *components = [calendar components:(NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay) fromDate:self];
    return [calendar dateFromComponents:components];
}

- (NSDate*)endOfDay {
    return [[[self addingDays:1] beginOfDay] addingSeconds:-1];
}

- (NSDate*)endOfWeek {
    NSCalendar *calendar = [[self class] sharedCalendar];
    NSDateComponents *weekdayComponents = [calendar components:NSCalendarUnitWeekday fromDate:self];
    NSDateComponents *componentsToAdd = [[NSDateComponents alloc] init];
    [componentsToAdd setDay:(7 - [weekdayComponents weekday])];
    return [calendar dateByAddingComponents:componentsToAdd toDate:self options:0];
}

- (BOOL)isLeapYear {
    NSDateComponents *components = [self dateComponents];
    if (components.year%400 == 0){
        return YES;
    } else if (components.year%100 == 0){
        return NO;
    } else if (components.year%4 == 0){
        return YES;
    }
    return NO;
}

- (NSString *)chineseYear {
    NSArray *chineseYears = [NSArray arrayWithObjects:
                             @"甲子", @"乙丑", @"丙寅", @"丁卯",  @"戊辰",  @"己巳",  @"庚午",  @"辛未",  @"壬申",  @"癸酉",
                             @"甲戌",   @"乙亥",  @"丙子",  @"丁丑", @"戊寅",   @"己卯",  @"庚辰",  @"辛己",  @"壬午",  @"癸未",
                             @"甲申",   @"乙酉",  @"丙戌",  @"丁亥",  @"戊子",  @"己丑",  @"庚寅",  @"辛卯",  @"壬辰",  @"癸巳",
                             @"甲午",   @"乙未",  @"丙申",  @"丁酉",  @"戊戌",  @"己亥",  @"庚子",  @"辛丑",  @"壬寅",  @"癸丑",
                             @"甲辰",   @"乙巳",  @"丙午",  @"丁未",  @"戊申",  @"己酉",  @"庚戌",  @"辛亥",  @"壬子",  @"癸丑",
                             @"甲寅",   @"乙卯",  @"丙辰",  @"丁巳",  @"戊午",  @"己未",  @"庚申",  @"辛酉",  @"壬戌",  @"癸亥", nil];
    
    NSDateComponents *components = [[[self class] chineseCalendar] components:NSCalendarUnitYear fromDate:self];
    return [chineseYears objectAtIndex:components.year-1];
}

- (NSString *)chineseMonth {
    NSArray *chineseMonths = [NSArray arrayWithObjects:
                            @"正月", @"二月", @"三月", @"四月", @"五月", @"六月", @"七月", @"八月",
                            @"九月", @"十月", @"冬月", @"腊月", nil];
    
    NSDateComponents *components = [[[self class] chineseCalendar] components:NSCalendarUnitMonth fromDate:self];
    return [chineseMonths objectAtIndex:components.month-1];
}

- (NSString *)chineseDay {
    NSArray *chineseDays = [NSArray arrayWithObjects:
                          @"初一", @"初二", @"初三", @"初四", @"初五", @"初六", @"初七", @"初八", @"初九", @"初十",
                          @"十一", @"十二", @"十三", @"十四", @"十五", @"十六", @"十七", @"十八", @"十九", @"二十",
                          @"廿一", @"廿二", @"廿三", @"廿四", @"廿五", @"廿六", @"廿七", @"廿八", @"廿九", @"三十",  nil];
    
    NSDateComponents *components = [[[self class] chineseCalendar] components:NSCalendarUnitDay fromDate:self];
    return [chineseDays objectAtIndex:components.day-1];
}

- (NSString*)chineseFullWeekdayName {
    NSArray *chineseWeekdyaNames = [NSArray arrayWithObjects:@"星期日", @"星期一", @"星期二", @"星期三", @"星期四", @"星期五", @"星期六", nil];
    return [chineseWeekdyaNames objectAtIndex:([self weekday] - [[self class] sharedCalendar].firstWeekday)];
}

- (NSString*)chineseShortWeekdayName {
    NSArray *chineseWeekdyaNames = @[@"周日", @"周一", @"周二", @"周三", @"周四", @"周五", @"周六"];
    return [chineseWeekdyaNames objectAtIndex:([self weekday] - 1)];
}
@end
